package com.sudo.service.admin.rpc.provider;

import com.sudo.common.component.SpringContextUtil;
import com.sudo.common.utils.ThreadLocalUtil;
import com.sudo.rpc.api.common.Constant;
import com.sudo.rpc.api.model.CallTask;
import com.sudo.rpc.api.model.RegistryServer;
import com.sudo.rpc.api.service.RmiSetServerService;
import com.sudo.rpc.api.utils.RpcRes;
import com.sudo.service.admin.service.LogAndEmailService;
import com.sudo.service.admin.service.SysServerNodeService;
import com.sudo.service.admin.service.SysServerNodeTaskService;
import com.sudo.service.aspect.VerifyTaskRequestAspect;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.RemoteServer;
import java.rmi.server.ServerNotActiveException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Map;

@Slf4j
@Service
public class RmiRegistryServiceImpl extends UnicastRemoteObject implements RmiSetServerService {

    @Resource
    private SysServerNodeService sysServerNodeService;

    @Resource
    private SysServerNodeTaskService sysServerNodeTaskService;

    @Resource
    private VerifyTaskRequestAspect verifyTaskRequestAspect;

    @Resource
    private LogAndEmailService logAndEmailService;

    public RmiRegistryServiceImpl() throws RemoteException {
        super();
    }

    // 执行器启动时调用，向管理端注册rmi地址
    @Override
    public void pushServer(RegistryServer registryServer) throws RemoteException {
        try {
            String clientHost = RemoteServer.getClientHost();
            String server = clientHost + ":" + registryServer.getPort();
            log.info("一个服务来注册：{}",server);

            sysServerNodeService.deleteAndSaveServerNode(server);
            sysServerNodeTaskService.deleteAndSaveServerNodeTask(server, registryServer);
        } catch (ServerNotActiveException e) {
            log.error("服务注册异常：",e);
        }
    }

    @Override
    public Object pullServer(String ip, Integer port) throws RemoteException {
        try {
            Registry remoteRegistry = LocateRegistry.getRegistry(ip, port);
            RmiSetServerService rmiSetServerService = (RmiSetServerService) remoteRegistry.lookup(Constant.registryCenter);
            return RpcRes.ok(rmiSetServerService.pullServer(ip, port));
        } catch (NotBoundException e) {
            log.error("服务未绑定异常：",e);
            return RpcRes.errorMsg("服务未绑定异常：" + e.getCause());
        }
    }

    @Override
    public Object callServer(CallTask callTask) throws RemoteException {
        try {
            Registry remoteRegistry = LocateRegistry.getRegistry(callTask.getIp(), callTask.getPort());
            RmiSetServerService rmiSetServerService = (RmiSetServerService) remoteRegistry.lookup(Constant.registryCenter);
            Object o = rmiSetServerService.callServer(callTask);

            // rpc任务调用后的 日志，邮件处理
            Map<String, Object> tlMap = ThreadLocalUtil.getTlMap();
            ThreadLocalUtil.removeTlMap();
            RpcRes rpcRes = (RpcRes) o;
            // 有回调
            if (rpcRes.getStatus().compareTo(Constant.callCode) == 0) {
                if (StringUtils.isNotBlank(callTask.getCallbackFun())) {
                    String[] beanMethod = callTask.getCallbackFun().split("/");

                    try{
                        Object targetBean = SpringContextUtil.getBean(beanMethod[0]);
                        // 找到带有三个参数的回调方法Integer jobId，CallTask callTask，RpcRes rpcRes
                        Method method = targetBean.getClass().getDeclaredMethod(beanMethod[1], Integer.class,CallTask.class,RpcRes.class);
                        method.invoke(targetBean, Integer.parseInt(tlMap.get("tl_jobId").toString()),callTask,rpcRes);
                        rpcRes.setStatus(200);
                        rpcRes.setMsg("回调成功");
                    }catch (NoSuchMethodException e){
                        rpcRes.setStatus(500);
                        rpcRes.setMsg("回调失败，找不到回调方法："+beanMethod[1]);
                        String exception = ExceptionUtils.getStackTrace(e);
                        rpcRes.setData(exception);
                        log.error("回调失败，找不到回调方法：{}",beanMethod[1],e);
                    } catch (InvocationTargetException e) {
                        rpcRes.setStatus(500);
                        rpcRes.setMsg("回调失败，调用方法"+ beanMethod[1] +"异常："+e.getCause());
                        String exception = ExceptionUtils.getStackTrace(e);
                        rpcRes.setData(exception);
                        log.error("回调失败，调用方法异常",e);
                    } catch (IllegalAccessException e) {
                        rpcRes.setStatus(500);
                        rpcRes.setMsg("回调失败，非法访问异常");
                        String exception = ExceptionUtils.getStackTrace(e);
                        rpcRes.setData(exception);
                        log.error("回调失败，非法访问异常",e);
                    } catch (NoSuchBeanDefinitionException e){
                        rpcRes.setStatus(500);
                        rpcRes.setMsg("回调失败，找不到bean异常");
                        String exception = ExceptionUtils.getStackTrace(e);
                        rpcRes.setData(exception);
                        log.error("回调失败，找不到bean异常",e);
                    }
                }else {
                    rpcRes.setStatus(500);
                    rpcRes.setMsg("调用成功，但缺少回调方法");
                    log.error("Rpc任务【{}】,{}-{}-{}-{}缺少回调方法.", tlMap.get("tl_jobId").toString(), callTask.getIp(), callTask.getPort(), callTask.getBeanName(), callTask.getMethodName());
                }
            }
            if (rpcRes.getStatus().compareTo(500) == 0){
                logAndEmailService.asyncRpcMethodJobLogAndEmail(tlMap,rpcRes);
            }
            return rpcRes;
        } catch (NotBoundException e) {
            log.error("服务未绑定异常：",e);
            return RpcRes.errorMsg("服务未绑定异常：" + e.getCause());
        }
    }
}
